package org.zhadoop.stream.cql.semanticanalyzer.parser.visitor;

import java.lang.reflect.Constructor;
import java.math.BigDecimal;

import org.antlr.v4.runtime.misc.NotNull;
import org.zhadoop.stream.cql.CQLConst;
import org.zhadoop.stream.cql.CQLUtils;
import org.zhadoop.stream.cql.semanticanalyzer.parser.CQLParser.BooleanValueContext;
import org.zhadoop.stream.cql.semanticanalyzer.parser.CQLParser.ConstBigDecimalValueContext;
import org.zhadoop.stream.cql.semanticanalyzer.parser.CQLParser.ConstDoubleValueContext;
import org.zhadoop.stream.cql.semanticanalyzer.parser.CQLParser.ConstFloatValueContext;
import org.zhadoop.stream.cql.semanticanalyzer.parser.CQLParser.ConstIntegerValueContext;
import org.zhadoop.stream.cql.semanticanalyzer.parser.CQLParser.ConstLongValueContext;
import org.zhadoop.stream.cql.semanticanalyzer.parser.CQLParser.ConstStingValueContext;
import org.zhadoop.stream.cql.semanticanalyzer.parser.CQLParser.UnaryOperatorContext;
import org.zhadoop.stream.cql.semanticanalyzer.parser.context.ConstantContext;
import org.zhadoop.streaming.exception.StreamingRuntimeException;

/**
 * 常量遍历
 * 
 * @author zwd
 *
 */
public class ConstantVisitor extends AbsCQLParserBaseVisitor<ConstantContext> {

	private ConstantContext context = null;

	private String unaryOperator = "";

	public ConstantVisitor() {
	}

	@Override
	protected ConstantContext defaultResult() {
		return context;
	}

	@Override
	public ConstantContext visitUnaryOperator(@NotNull UnaryOperatorContext ctx) {
		if (ctx.getText().equals("-")) {
			unaryOperator = ctx.getText();
		}
		return context;
	}

	@Override
	public ConstantContext visitConstIntegerValue(@NotNull ConstIntegerValueContext ctx) {
		Class<?> type = Integer.class;
		Object value = createConstInstance(unaryOperator + ctx.getText(), type);
		context = new ConstantContext(type, value);
		return context;
	}

	@Override
	public ConstantContext visitConstLongValue(@NotNull ConstLongValueContext ctx) {
		Class<?> type = Long.class;
		Object value = createConstInstance(unaryOperator + ctx.getText().substring(0, ctx.getText().length() - 1),
				type);
		context = new ConstantContext(type, value);
		return context;
	}

	@Override
	public ConstantContext visitConstFloatValue(@NotNull ConstFloatValueContext ctx) {
		Class<?> type = Float.class;
		Object value = createConstInstance(unaryOperator + ctx.getText().substring(0, ctx.getText().length() - 1),
				type);
		context = new ConstantContext(type, value);
		return context;
	}

	@Override
	public ConstantContext visitConstDoubleValue(@NotNull ConstDoubleValueContext ctx) {
		Class<?> type = Double.class;
		Object value = createConstInstance(unaryOperator + ctx.getText().substring(0, ctx.getText().length() - 1),
				type);
		context = new ConstantContext(type, value);
		return context;
	}

	@Override
	public ConstantContext visitConstBigDecimalValue(@NotNull ConstBigDecimalValueContext ctx) {
		Class<?> type = BigDecimal.class;
		String number = ctx.getText().substring(0, ctx.getText().length() - CQLConst.I_2);
		Object value = createConstInstance(unaryOperator + number, type);
		context = new ConstantContext(type, value);
		return context;
	}

	@Override
	public ConstantContext visitConstStingValue(@NotNull ConstStingValueContext ctx) {
		Class<?> type = String.class;
		Object value = createConstInstance(CQLUtils.cqlStringLiteralTrim(ctx.getText()), type);
		context = new ConstantContext(type, value);
		return context;
	}

	@Override
	public ConstantContext visitBooleanValue(@NotNull BooleanValueContext ctx) {
		Class<?> type = Boolean.class;
		Object value = createConstInstance(ctx.getText(), type);
		context = new ConstantContext(type, value);
		return context;
	}

	private Object createConstInstance(String value, Class<?> clazz) {
		Object resValue = null;
		try {
			Constructor<?> constructor = clazz.getConstructor(String.class);
			resValue = constructor.newInstance(value);
		} catch (Exception e) {
			throw new StreamingRuntimeException(e);
		}
		return resValue;
	}
}
